package coin

import (
	"global/model"
	"global/libs/structs"
	"sync"
	"global/core"
	"strings"
)

const (
	CoinAdd 	= iota
	CoinDel
	CoinUpdate
)

type CoinHandler struct {
	ctx 			*core.Context
	coins 			map[string]*model.Coin
	coinHandles 	map[string]*AnalysisCoin
	exchanges 		map[string]*model.Exchange
	symbols 		map[string]map[string]structs.Symbol
	markets 		map[string]map[string]interface{}

	coinSort 		*CoinSort

	mux 			sync.Mutex


	// 通道获取 exchange 分析的结果
	ExchangeCoinPrice 	chan *structs.CoinUsdPriceChannelData

	// 保存的记录
	CoinResults			map[string]map[string]*structs.CoinTicker
}

func NewCoinHandle() *CoinHandler {
	return &CoinHandler{
		coins: 			make(map[string]*model.Coin),
		coinHandles: 	make(map[string]*AnalysisCoin),
		exchanges: 		make(map[string]*model.Exchange),
		symbols: 		make(map[string]map[string]structs.Symbol),
		markets: 		make(map[string]map[string]interface{}),

		ExchangeCoinPrice: 		make(chan *structs.CoinUsdPriceChannelData, 100),
		CoinResults: 			make(map[string]map[string]*structs.CoinTicker),
	}
}

// 一些初始化操作
func (ch *CoinHandler) Init(
	ctx *core.Context,
	coins map[string]*model.Coin,
	exchanges map[string]*model.Exchange,
	markets map[string]map[string]interface{},
	symbols map[string]map[string]structs.Symbol) {

		ch.ctx = ctx
		ch.symbols = symbols
		ch.exchanges = exchanges
		ch.coins = coins
		ch.markets = markets

		ch.coinSort = NewCoinSort(ctx.GetBaseRedis())
		ch.coinSort.InitCoinTickers(ch.coins)
		go ch.coinSort.Run()

		go func() {
			for {
				select {
				case coinPrice := <- ch.ExchangeCoinPrice:
					go ch.handleExchangeCoinPrice(coinPrice)
				}
			}
		}()
}

func (ch *CoinHandler) handleExchangeCoinPrice(coinPrice *structs.CoinUsdPriceChannelData) {
	ch.mux.Lock()
	defer ch.mux.Unlock()
	for c, p := range coinPrice.Data {
		if _, ok := ch.coins[c]; ok {
			data := &coinUsdPriceChannelData{
				ExchangeName: 		coinPrice.Exchange,
				Coin: 				c,
				UsdPrice: 			p,
			}
			ch.coinHandles[c].UsdPrice <- data
		}
	}
}

func (ch *CoinHandler) Run() {
	for _, v := range ch.coins {
		go func(coin *model.Coin) {
			ch.newAnalysisCoin(coin)
		}(v)
	}
}

func (ch *CoinHandler) newAnalysisCoin(coin *model.Coin)  {
	analysis := NewAnalysisCoin(ch.ctx.GetBaseRedis(),
		ch.coinSort, coin, ch.symbols, ch.markets)
	go analysis.Start()

	slug := strings.ToLower(coin.Symbol)
	ch.mux.Lock()
	ch.coinHandles[slug] = analysis
	ch.mux.Unlock()
}

func (ch *CoinHandler) UpdateCoin(opt int, coin *model.Coin) {
	slug := strings.ToLower(coin.Symbol)

	ch.mux.Lock()
	defer ch.mux.Unlock()

	if _, ok := ch.coinHandles[slug]; ok && opt == CoinAdd {
		return
	} else if !ok && (opt == CoinUpdate || opt == CoinDel) {
		return
	}

	switch opt {
	case CoinAdd:
		ch.newAnalysisCoin(coin)
	case CoinUpdate:
		ch.coinHandles[slug].UpdateCoinMetaData <- coin
	case CoinDel:
		ch.coinHandles[slug].ExitSignal <- true
	}
}

func (ch *CoinHandler) UpdateExchange(opt int, exchange *model.Exchange) {
	// ....
}